上一期,我们一起学习了TensorFlow在训练深度网络的时候怎么解决梯度消失或梯度爆炸的问题,以及怎么尽可能的减少训练时间。
这期我们继续学习训练深度网络时的一大神器----优化器。学习的路上,我们多多交流,共同进步。本期主要内容如下:
Momentum optimization
Nesterov Accelerated Gradient
AdaGrad
RMSProp
Adam Optimization
1. 回顾
我们知道在训练一个比较大的深度神经网络的时候,速度上一般都是比较慢的。通过上期的学习,我们已经知道有4种方法可以加速我们的训练过程,如下:
a. 选择一个合适的权重初始化策略
b. 用一个合适的激活函数
c. 运用Batch Normalization策略
d. 复用之前的网络模型
但是今天我们要学习的是另外一个加速神器--优化器,它要比一般的梯度下降算法快很多。我们这里主要介绍几种常见的优化器,其中包括:Momentum optimization,Nesterov Accelerated Gradient,AdaGrad,RMSProp,Adam Optimization。
2. Momentum optimization
2.1 原理
momentum optimization可以翻译为动量优化器,该优化器背后的思想很简单: 假设一个圆球从一个斜坡上滚下去,一开始速度会很慢,但是随着时间的增加,速度会越来越快,考虑到摩擦力和空气阻力,最终会达到一个恒定的速度(空气阻力跟速度的平方成正比)。这就是momentum optimization 背后的思想。跟一般的梯度下降法相比,显然动量优化速度更快。
我们再回顾下一般梯度下降权重的更新是用权重直接减去学习率乘以梯度:
这种更新权重的方式,并不关心之前的梯度,只根据当前梯度值进行更新。如果当前梯度比较小的话,那么寻优的过程就比较费时。
动力优化根据这一缺点对一般的梯度下降法进行了改进。动力优化更多的考虑了之前的梯度信息,在每一次的迭代中,都会把当前梯度信息加到动力向量m中,最终根据减去动力向量来更新权重,如下公式:
换句话说,这里把梯度当做是加速度而并不是速度,为了模拟一些摩擦力和阻力来防止速度变得过大,该算法增加了一个超参数β,该值的取值范围为0~1,当β=0时表示较高的阻力,此时梯度的更新等同于一般的梯度优化。当β=1的时候表示没有阻力,此时梯度更新最快,一般情况下该值设置为0.9.
从上面公式可以看出,假如梯度恒定为∇的话,权重更新的最终速度为η∇/(1−β)。假如β=0.9的话,那么momentum optimization的最终优化速度是一般梯度下降的10倍左右。这就使的动力优化比一般梯度优化能够更快的逃离平坦区域。
由于动力加速度的存在,所以在寻优的时候可能会超过最优点一点,然后返回,再超过,再返回最终稳定在最优点。这就是为什么要在算法中加入超参数β的一个原因,它能够减少震荡加速收敛。
2.2 实现
在TensorFlow中实现Momentum Optimization比较简单,如下:
1optimizer = tf.train.MomentumOptimizer(learning_rate=learning_rate,
2 momentum=0.9)
动力优化的一个缺点就是多了一个超参数β去调节。然而,这个超参数一般情况下设置为0.9就能够很好的工作,并不需要经常去调节。
3. Nesterov Accelerated Gradient
3.1 原理
Nesterov Accelerated Gradient(NAG)算法,其实是对Momentum Optimization的一个小小的改进,在动力优化中,更新动力变量m是在当前(θ)的梯度上进行更新的,而在NAG算法中,对动力变量的更新在动力方向上稍微提前了一些(θ+βm),如下:
上面的改进是可行的原因就在于,Momentum Optimization中的动力向量m的方向是指向最优点的,因此用更前一点的梯度来代替当前的梯度去更新动力向量更为精确。如下图:
上图中,∇1代表损失函数在起始点θ的梯度,而∇2代表损失函数在点θ+βm的梯度值,可以看到NAG更接近最优点,随着时间的累积,NAG会比动力优化器明显的更快一些。此外我们还可以看到,当动力向量推动权重接近最优值的时候,∇1会继续加速推动,使得远离最优值,而∇2则已经开始往回拉了,这就减少了震荡进而使得更快收敛。
3.2 实现
在training深度网络的时候,NAG通常会比Momentum Optimization更快收敛,用起来也比较简单只需要将动力优化器中设置参数use_nesterov=True即可,如下:
1optimizer = tf.train.MomentumOptimizer(learning_rate=learning_rate,
2 momentum=0.9, use_nesterov=True)
4. AdaGrad
4.1 原理
考虑到之前介绍的细长碗的最优化这个问题,一般的梯度优化会在陡峭的区域快速下降,而在平坦区域慢慢走向最优值。如果算法能够提前监测到这种情况就会更好,就可以在陡峭的地方慢慢下降(防止错过最优点),在平坦区域快速通过,这样就能更快的找到最优点。AdaGrad算法就是通过衰减学习率来进行达到这个目的的。公式原理如下:
上面公式1中在s中累加了梯度的平方,(⊗表示矩阵中对应元素相乘),而在公式2中和之前的梯度下降比较类似,唯一不同的是对梯度向量进行了衰减或者说是对学习率η做了衰减(⊘表示矩阵中对应元素相除,而ε则是防止除数为0,通常设置为10^(−10))。
换句话说就是AdaGrad算法对学习率进行了自适应化,当梯度比较大的时候,学习率就比较小,而当梯度比较小的时候,学习率就比较大。如下图,该算法能够更明显的向最优点逼近。
然而事实证明,AdaGrad算法在一些简单的二项式问题上表现优异,但是在training深度网络的时候,由于学习率衰减过多,常常会过早停止寻优。因此,尽管TensorFlow中有提供该方法AdaGradOptimizer,但是不建议用该优化器去训练深度网络。因此这里就不写出实现代码了。
5. RMSProp
5.1 原理
尽管AdaGrad算法衰减过快而导致无法收敛到最优点的问题,RMSProp算法通过修改AdaGrad算法第一步的梯度累加方式,改累加所有的梯度为对累加的梯度乘以一个衰减系数,如下公式:
可知,该方法又多了一个超参数衰减率β,一般设置为β=0.9。理解了AdaGrad算法,这里就不再过多解释了。
5.2 实现
当然,TensorFlow对该算法也是有提供的,如下:
1optimizer = tf.train.RMSPropOptimizer(learning_rate=learning_rate,
2 momentum=0.9, decay=0.9, epsilon=1e-10)
这个方法的表现还是不错的,在简单问题上表现优于AdaGrad算法,一般情况下性能也优于Momentum Optimization和NAG方法。事实上,在Adam算法出现之前,这个方法是一般训练网络时候的最优选则。
6. Adam Optimization
6.1 原理
Adam代表adaptive moment estimation,结合了Momentum Optimization和RMSProp的思想。运用了动力优化方法中的利用历史梯度信息,和RMSProp中利用历史历史梯度的平方的相关信息,公式如下:
从上面1,2,5公式可以看出,该算法跟Momentum Optimization和RMSProp特别像,唯一不同的是在公式1中运用了历史梯度指数衰减的均值而不是历史梯度指数衰减的和。公式3,4其实是一个小技巧点,因为一般m和s会被初始化为0,所以在training开始的时候回一直偏向0,公式3,4能够在training初期快速提高这两个变量值。
上公式中多了3个超参数β1,β2,ε,这三个参数一般设置为0.9,0.99和10^(−8).
6.2 实现
在Tensorflow中用法都是很简单,所有参数都为默认值的情况下如下:
1optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
其实Adam算法是一个自动调节学习率的算法,一般可以将学习率设置为0.001.事实证明该算法在一般深度网络中是优选择。
7. 小结
我们从一般梯度下降出发,一起学习了最近比较常见的优化器,包括Momentum Optimization, Nesterov Accelerated Gradient, AdaGrad, RMSProp和Adam Optimization。其中Adam算法是目前在training深度网络中的优选。
(如需更好的了解相关知识,欢迎加入智能算法社区,在“智能算法”公众号发送“社区”,即可加入算法微信群和QQ群)